#include "FormCalib.h"
#include "ui_FormCalib.h"
#include <QMessageBox>

FormCalib::FormCalib(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::FormCalib)
{
    ui->setupUi(this);
    setWindowTitle("标定窗口");
    InitChart();
    InitListTable();
}

FormCalib::~FormCalib()
{
    delete ui;
}

void FormCalib::InitChart()
{
    ui->Chart->clearItems();

    /* Used for higher performance (see QCustomPlot real time example) */
    ui->Chart->setNotAntialiasedElements (QCP::aeAll);
    QFont font;
    font.setStyleStrategy (QFont::NoAntialias);
    font.setPixelSize(10);
    font.setFamily("Microsoft YaHei");
    /* X Axis: Style */
    ui->Chart->xAxis->grid()->setPen (QPen(QColor (170, 170, 170, 255), 1, Qt::DotLine));
    ui->Chart->xAxis->grid()->setSubGridPen (QPen(QColor (170, 170, 170, 255), 1, Qt::DotLine));
    ui->Chart->xAxis->grid()->setSubGridVisible (true);
    ui->Chart->xAxis->setBasePen (QPen (QColor (100, 100, 100, 255),2));
    ui->Chart->xAxis->setTickPen (QPen (QColor (170, 170, 170, 255)));
    ui->Chart->xAxis->setSubTickPen (QPen (QColor (100, 100, 100, 255)));
    ui->Chart->xAxis->setUpperEnding (QCPLineEnding::esSpikeArrow);
    ui->Chart->xAxis->setTickLabelColor (QColor (100, 100, 100, 255));
    ui->Chart->xAxis->setTickLabelFont (font);

    /* Y Axis */
    ui->Chart->yAxis->grid()->setPen (QPen(QColor (170, 170, 170, 255), 1, Qt::DotLine));
    ui->Chart->yAxis->grid()->setSubGridPen (QPen(QColor (170, 170, 170, 255), 1, Qt::DotLine));
    ui->Chart->yAxis->grid()->setSubGridVisible (true);
    ui->Chart->yAxis->setBasePen (QPen (QColor (100, 100, 100, 255),2));
    ui->Chart->yAxis->setTickPen (QPen (QColor (170, 170, 170, 255)));
    ui->Chart->yAxis->setSubTickPen (QPen (QColor (170, 170, 170, 255)));
    ui->Chart->yAxis->setUpperEnding (QCPLineEnding::esSpikeArrow);
    ui->Chart->yAxis->setTickLabelColor (QColor (100, 100, 100, 255));
    ui->Chart->yAxis->setTickLabelFont (font);
    ui->Chart->yAxis->setLabelColor(QColor (100, 100, 100, 255));

    ui->Chart->setInteraction (QCP::iRangeDrag, true);
    ui->Chart->setInteraction (QCP::iRangeZoom, true);
    ui->Chart->setInteraction (QCP::iSelectPlottables, true);
    //ui->Chart->setInteraction (QCP::iSelectLegend, true);
    //ui->Chart->axisRect()->setRangeDrag (Qt::Horizontal);
    //ui->Chart->axisRect()->setRangeZoom (Qt::Horizontal);

    /* Legend 图例设置*/
    QFont legendFont;
    legendFont.setPixelSize(10);
    legendFont.setFamily("Microsoft YaHei");
    ui->Chart->legend->setVisible (true);
    ui->Chart->legend->setFont (legendFont);
    ui->Chart->legend->setBrush (QColor(255,255,255,0));
    ui->Chart->legend->setBorderPen(Qt::NoPen);
    ui->Chart->axisRect()->insetLayout()->setInsetAlignment (0, Qt::AlignTop|Qt::AlignLeft);
    ui->Chart->legend->setFillOrder(QCPLayoutGrid::foColumnsFirst);

    QPen line1;
    line1.setWidth(1);
    line1.setColor(QColor(Qt::blue));

    ui->Chart->addGraph();
    ui->Chart->graph()->setName(tr("原始点"));
    ui->Chart->graph()->setPen(line1);
    //ui->Chart->graph()->setAdaptiveSampling(true);
    ui->Chart->graph()->setLineStyle(QCPGraph::LineStyle::lsNone);
    ui->Chart->graph()->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ScatterShape::ssDisc, 6));

    QPen line2;
    line2.setWidth(2);
    line2.setColor(QColor(Qt::red));
    line2.setStyle(Qt::PenStyle::DashLine);

    ui->Chart->addGraph();
    ui->Chart->graph()->setName(tr("拟合线"));
    ui->Chart->graph()->setPen(line2);
    //ui->Chart->graph()->setAdaptiveSampling(true);

    QPen line3;
    line3.setWidth(1);
    line3.setColor(QColor(Qt::green));

    ui->Chart->addGraph();
    ui->Chart->graph()->setName(tr("选择点"));
    ui->Chart->graph()->setPen(line3);
    //ui->Chart->graph()->setAdaptiveSampling(true);
    ui->Chart->graph()->setLineStyle(QCPGraph::LineStyle::lsNone);
    ui->Chart->graph()->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ScatterShape::ssDisc, 4));
}

void FormCalib::InitListTable()
{
    ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
    ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
    QFont font;
    font.setPixelSize(13);
    font.setBold(true);
    font.setFamily("Microsoft YaHei");
    QStringList headerText={"原始值","实际值"};
    ui->tableWidget->setColumnCount(headerText.count());
    for (int i = 0; i < headerText.count(); i++)
    {
        QTableWidgetItem *headerItem = new QTableWidgetItem(headerText.at(i));
        headerItem->setFont(font);
        ui->tableWidget->setHorizontalHeaderItem(i, headerItem);
    }

    for (int i = 0; i < MaxPiont; i++)
    {
        ui->tableWidget->insertRow(i);
        ui->tableWidget->setRowHeight(i,25);
    }
}
bool compareBarSource(const SCalibData &barAmount1, const SCalibData &barAmount2)
{
    if (barAmount1.Source < barAmount2.Source)
    {
        return true;
    }
    else
    return false;
}
void FormCalib::UpdateTable()
{
    //更新chart
    ui->Chart->graph(0)->data()->clear();
    ui->Chart->graph(1)->data()->clear();

    //更新table
    ui->tableWidget->clearContents();

    //CalibSourceList排序
    qSort(s_CalibList.begin(), s_CalibList.end(), compareBarSource);

    uint iRow = 0;
    double sourceX[MaxPiont];
    double sourceY[MaxPiont];

    for (int i = 0; i < s_CalibList.count(); ++i)
    {
        AddItemContent(i,0,QString::number(s_CalibList.at(i).Source));
        AddItemContent(i,1,QString::number(s_CalibList.at(i).ActValue));

        sourceX[iRow]=s_CalibList.at(i).Source;
        sourceY[iRow]=s_CalibList.at(i).ActValue;
        ui->Chart->graph(0)->addData(sourceX[iRow],sourceY[iRow]);
        iRow++;
    }

    //标定从新绘制曲线
    if(ClibStyle==line&&iRow>1)
    {
        LinearFit<double>  Linear;
        LinearFit<double>::Points vect;

        for(int i=0;i<iRow;i++)
            vect.insert(std::map<double, double>::value_type(sourceX[i],sourceY[i]));

        Linear.fit(&vect);
        double k=Linear.getSlope();
        double b=Linear.getIntercept();
        double r=Linear.getRegressionCoefficient();

        ui->label_Exp->setText(QString("拟合公式:y=%1x+%2 拟合优度:%3").arg(k).arg(b).arg(r));
        s_CalibRltList.clear();

        s_CalibRltList.append(SCalibRlt(k,b));

        ui->Chart->graph(1)->addData(0,b);
        ui->Chart->graph(1)->addData(s_CalibList.last().Source,s_CalibList.last().Source*k+b);
    }
    else if(ClibStyle==lines&&iRow>2)
    {
        s_CalibRltList.clear();
        SCalibRlt linear;
        for(int i=0;i<iRow;i++)
        {
            ui->Chart->graph(1)->addData(sourceX[i],sourceY[i]);
            if(sourceX[i+1]==sourceX[i])
            {
                QMessageBox::information(this, tr("警告"), tr("原始值总和不能相同！"));
                return;
            }
            if(i+1<iRow)
            {
                linear.K=(sourceY[i+1]-sourceY[i])/(sourceX[i+1]-sourceX[i]);
                linear.B=sourceY[i]-linear.K*sourceX[i];
            }
            else if(i+1==iRow)
            {
                linear.K=(sourceY[i]-sourceY[i-1])/(sourceX[i]-sourceX[i-1]);
                linear.B=sourceY[i]-linear.K*sourceX[i];
            }
            s_CalibRltList.push_back(linear);
        }
    }
    ui->Chart->rescaleAxes(true);
    ui->Chart->replot();
}
//标定单位
void FormCalib::on_comboBox_Unit_activated(int index)
{
    ClibUnit=(eUnit)index;
}

//拟合方式
void FormCalib::on_comboBox_Style_activated(int index)
{
    ClibStyle=(eStyle)index;
    UpdateTable();
}
//更新表格
void FormCalib::AddItemContent(int row, int column, QString content)
{
    QTableWidgetItem *item = new QTableWidgetItem (content);
    item->setTextAlignment(Qt::AlignCenter | Qt::AlignVCenter);
    ui->tableWidget->setItem(row, column, item);
    ui->tableWidget->selectRow(row);
}

void FormCalib::ReadFileCalib(QString file)
{
    QDataStream Stream;
    QFile FileSave;
    FileSave.setFileName(file);
    if(FileSave.open(QIODevice::ReadOnly))
    {
        Stream.setDevice(&FileSave);
        Stream.setVersion(QDataStream::Qt_5_13);
        int unit,style;
        Stream>>unit;   //长度
        Stream>>style;  //压强

        ClibUnit=(eUnit)unit;
        ClibStyle=(eStyle)style;

        QList<double> clib;
        Stream>>clib;
        s_CalibList.clear();
        SCalibData source;
        for (int i = 0; i < clib.count()/2; ++i)
        {
            source.Source=clib.at(i*2+0);
            source.ActValue=clib.at(i*2+1);
            s_CalibList.append(source);
        }
        FileSave.close();
    }
}

void FormCalib::WriteFileCalib(QString file)
{
    QDataStream Stream;
    QFile FileSave;
    FileSave.setFileName(file);
    if(FileSave.open(QIODevice::WriteOnly))
    {
        Stream.setDevice(&FileSave);
        Stream.setVersion(QDataStream::Qt_5_13);
        int unit,style;

        unit=ClibUnit;
        style=ClibStyle;

        Stream<<unit;   //长度
        Stream<<style;  //压强

        QList<double> clib;
        for (int i = 0; i < s_CalibList.count(); ++i)
        {
            clib.append(s_CalibList.at(i).Source);
            clib.append(s_CalibList.at(i).ActValue);
        }

        Stream<<clib;

        FileSave.close();
    }
}
//添加点
void FormCalib::on_pushButton_AddData_clicked()
{
    SCalibData s_Calib;
    s_Calib.Source=ui->spinBox_Source->value();
    s_Calib.ActValue=ui->doubleSpinBox_Act->value();
    s_CalibList.append(s_Calib);
    UpdateTable();
}
//删除点
void FormCalib::on_pushButton_DeleteRow_clicked()
{
    if(ui->tableWidget->item(TableSelect,0)==nullptr)   //判断是否有数据
        return;

    if(QMessageBox::question(this, tr("询问"), tr("删除当前点?"),QMessageBox::Yes|QMessageBox::No)==QMessageBox::No)
        return;
    SCalibData s_Calib;
    s_Calib.Source=s_CalibList.at(TableSelect).Source;
    s_Calib.ActValue=s_CalibList.at(TableSelect).ActValue;

    s_CalibList.removeAt(TableSelect);

    UpdateTable();
}

//选中某个点
void FormCalib::on_tableWidget_cellClicked(int row, int column)
{
    ui->Chart->graph(2)->data()->clear();
    if(ui->tableWidget->item(row,0)!=0)
    {
        TableSelect=row;
        if(ui->tableWidget->item(row,0)->text()!="")
        {
            SCalibData s_Calib;
            s_Calib.Source=s_CalibList.at(TableSelect).Source;
            s_Calib.ActValue=s_CalibList.at(TableSelect).ActValue;

            int index=0;
            for (int i = 0; i < s_CalibList.count(); ++i)
            {
                if(s_Calib.Source==s_CalibList.at(i).Source)
                {
                    index=i;
                    break;
                }
            }
            ui->Chart->graph(2)->addData(s_CalibList.at(index).Source,s_CalibList.at(index).ActValue);
        }
    }
    ui->Chart->replot();
}

//导入标定数据
void FormCalib::on_pushButton_Import_clicked()
{
    //将当前文件拷贝到库目录,直接覆盖
    QString curPath =QDir::currentPath()+"/CalibFile";
    QDir dir(curPath);
    if(!dir.exists())
    {
        dir.mkpath(curPath);
    }
    QString FileName = QFileDialog::getOpenFileName(this,
                                                    tr("请选择导入标定文件路径"),
                                                    curPath,
                                                    tr("*.clib"));
    if(!FileName.isEmpty())
    {
        ReadFileCalib(FileName);
        ui->comboBox_Unit->setCurrentIndex(ClibUnit);
        ui->comboBox_Style->setCurrentIndex(ClibStyle);
        UpdateTable();
    }
}
//导出数据
void FormCalib::on_pushButton_Export_clicked()
{
    if(s_CalibList.count()<2)
    {
        QMessageBox::information(this, QStringLiteral("提示"), QStringLiteral("没有标定数据!"));
        return;
    }
    //将当前文件拷贝到库目录,直接覆盖
    QString curPath =QDir::currentPath()+"/CalibFile";
    QDir dir(curPath);
    if(!dir.exists())
    {
        dir.mkpath(curPath);
    }
    QString FileName = QFileDialog::getSaveFileName(this,
                                                    tr("请选择导出标定文件路径"),
                                                    curPath+"/"
                                                    +QString::number(s_CalibList.last().ActValue)    //量程
                                                    +"_"
                                                    +ui->comboBox_Unit->currentText()                //单位
                                                    ,"*.clib");
    if(!FileName.isEmpty())
    {
        WriteFileCalib(FileName);
    }
}

